//******************************************************************/
//				SdCard控制模块
//版本说明:
//V0.1		2019-08-01	11:00	yshao	灯饰控制器SdCard控制
//******************************************************************/
//`define	BOOT_MODE	1
module sdcard_top(
		//复位&时钟
		input	wire		resetb,
		input	wire		sclk,
		input	wire		clk_25M,
		
		input	wire	[20:0]	time_us,
		input	wire	[20:0]	sync_us,
		
		//SD接口状态
		output	wire	[7:0]	sd_state,

		//SD卡接口
		output	wire		sd_clk,
		inout	tri		sd_cmd_sdi,
		input	wire		sd_dat0_sdo,
		input	wire		sd_dat1,
		input	wire		sd_dat2,
		inout	wire		sd_dat3_cs,
		input	wire		sd_cd,
		input	wire		sd_wp,

		//MCU控制接口
		input	wire		mcu_sd_en,
		input	wire		mcu_fpga_ctrl,
		input	wire		mcu_spi_clk,
		input	wire		mcu_spi_mosi,
		output	wire		mcu_sd_miso,
		
		//MCU设置接口
	        input	wire		cmd_d_ok,
	        input	wire	[31:0]	cmd_addr,
	        input	wire	[7:0]	cmd_data,

		//sd播放使能
		output	reg		input_local,
		output	wire		force_dis_en,
		output	wire		force_send_play,
		
		//SD显示信号
		output	wire		vs_sd,
		output	wire		h_start_sd,
		output	wire	[10:0]	h_num_sd,
		output	wire		ds_sd,
		output	wire	[7:0]	data_sd,

		//网口发送信号
		output	wire		send_flag_sd,
		output	wire		pre_flag_sd,
		output	wire	[7:0]	send_data_sd,
		
		//调试接口
		output	wire	[31:0]	tout
		);

//****************************************************************
//		内部信号
//****************************************************************
//sd卡状态
reg	[5:0]	sdcard_state;
reg	[6:0]	sd_valid_count;
reg		sd_cd_sclk_a, sd_cd_sclk_b, sd_cd_sclk;
wire		sd_valid, sd_init_ok;

//显示缓冲切换
wire		sd_play_clk, sd_play_cmd_oe, sd_play_cmd_out;
wire		sd_mcu_clk, sd_mcu_cmd_oe, sd_mcu_cmd_out;
reg		sd_clk_out, sd_cmd_oe, sd_cmd_out;
wire	[3:0]	sd_dat_in, sd_dat_mcu;
reg	[3:0]	sd_dat_dis;

//帧读取
wire		f_start, f_work, sd_work, mcu_play_en, sd_play_en;
wire	[40:0]	f_addr;
wire	[23:0]	f_size;
wire	[10:0]	h_size;
wire	[12:0]	l_size;

//调试信号
wire	[15:0]	sd_tout, mcu_tout;
wire	[31:0]	sd_f_tout;

//********************************************************//
//			参数定义
//********************************************************//
parameter SD_IDLE	=6'b000001;
parameter SD_WAIT_CARD	=6'b000010;
parameter SD_INIT_PRE	=6'b000100;
parameter SD_WAIT_INIT	=6'b001000;
parameter SD_MCU_INIT	=6'b010000;
parameter SD_INIT_DONE	=6'b100000;

//**************************************************************
//		   SD卡状态
//**************************************************************
assign	sd_state[0] = sd_valid;
assign	sd_state[1] = ~sd_init_ok;
assign	sd_state[6:2] = 0;
assign	sd_state[7] = sd_work;

//**************************************************************
//		   SD卡控制状态机
//**************************************************************
//sdcard状态机
always @(posedge sclk or negedge resetb)
	if (resetb == 0)
		sdcard_state <= SD_IDLE;
	else if (sd_cd_sclk == 1)
		sdcard_state <= SD_IDLE;
	else		
		case (sdcard_state)
			SD_IDLE:	
				sdcard_state <= SD_WAIT_CARD;
			SD_WAIT_CARD:					//等待SD卡稳定插入
				if (sd_valid == 1)
					sdcard_state <= SD_INIT_PRE;
			SD_INIT_PRE:					//确保当前不处在MCU配置SD卡状态
				if (mcu_sd_en == 0)
					sdcard_state <= SD_WAIT_INIT;
			SD_WAIT_INIT:					//等待MCU配置SD卡开始
				if (mcu_sd_en == 1)
					sdcard_state <= SD_MCU_INIT;
			SD_MCU_INIT:					//等待MCU配置SD卡结束
				if (mcu_sd_en == 0)
					sdcard_state <= SD_INIT_DONE;
			SD_INIT_DONE:					//SD卡播放模式
				sdcard_state <= SD_INIT_DONE;
			default:
				sdcard_state <= SD_IDLE;
		endcase

//SD卡拔出信号检测
always @(posedge sclk) begin
	sd_cd_sclk_a <= sd_cd;
	sd_cd_sclk_b <= sd_cd_sclk_a;
	sd_cd_sclk <= sd_cd_sclk_b;
end
	
//SD卡持续有效时间计数
always @(posedge sclk)
	if (sdcard_state == SD_IDLE)
		sd_valid_count <= 0;
	else if ((sync_us[10] == 1) && (sd_valid == 0))
		sd_valid_count <= sd_valid_count + 1;

//SD卡有效标志
assign	sd_valid = sd_valid_count[6];

//SD卡可以播放标志
assign	sd_init_ok = sdcard_state[5];

//**************************************************************
//		   SD卡控制选通
//**************************************************************
always	@( * )
	if (sdcard_state == SD_MCU_INIT) begin
		sd_clk_out <= sd_mcu_clk;
		sd_cmd_oe <= sd_mcu_cmd_oe;
		sd_cmd_out <= sd_mcu_cmd_out;
		end
	else if (sdcard_state != SD_INIT_DONE) begin
		sd_clk_out <= 1'b0;
		sd_cmd_oe <= 1'b0;
		sd_cmd_out <= 1'b1;
		end
	else if (sd_work == 1) begin 
		sd_clk_out <= sd_play_clk;
		sd_cmd_oe <= sd_play_cmd_oe;
		sd_cmd_out <= sd_play_cmd_out;
		end
	else if (mcu_sd_en == 1) begin 
		sd_clk_out <= sd_mcu_clk;
		sd_cmd_oe <= sd_mcu_cmd_oe;
		sd_cmd_out <= sd_mcu_cmd_out;
		end
	else begin
		sd_clk_out <= 1'b0;
		sd_cmd_oe <= 1'b0;
		sd_cmd_out <= 1'b1;
		end

//SD卡输出控制
assign	sd_clk = sd_clk_out;
assign	sd_cmd_sdi = (sd_cmd_oe == 1)?sd_cmd_out:1'bz;

//SD卡输入控制
assign	sd_cmd_in = sd_cmd_sdi;
assign	sd_dat_in = {sd_dat3_cs, sd_dat2, sd_dat1, sd_dat0_sdo};

always	@( * )
	if (mcu_play_en == 0)
		sd_dat_dis <= sd_dat_in;
	else
		sd_dat_dis <= sd_dat_mcu;

//**************************************************************
//		   本地播放状态判断
//**************************************************************
always @(posedge clk_25M or negedge resetb)
	if(resetb==0)
		input_local <= 0;
	else if (f_work == 1)
		input_local <= 1;
	else if (sd_play_en == 0)
		input_local <= 0;

//**************************************************************
//		   mcu通过FPGA直接控制SD卡
//**************************************************************
mcu_sd_cnt mcu_sd_cnt(
		.resetb(resetb),
		.sclk(sclk),
                
		//MCU控制接口
		.mcu_sd_en(mcu_sd_en),
		.mcu_fpga_ctrl(mcu_fpga_ctrl),
		
		.mcu_spi_clk(mcu_spi_clk),
		.mcu_spi_mosi(mcu_spi_mosi),
		.mcu_spi_miso(mcu_sd_miso),
                
		//SD卡接口
		.sd_clk(sd_mcu_clk),
		.sd_cmd_oe(sd_mcu_cmd_oe),
		.sd_cmd_out(sd_mcu_cmd_out),
		.sd_cmd_in(sd_cmd_in),
		.sd_dat_oe(),
		.sd_dat_out(),
		.sd_dat_in(sd_dat_in),
		
		.tout(mcu_tout)
		);

//******************************************************************/
//			 SD卡脱机播放
//******************************************************************/
//播放控制接口
sd_main_ctrl sd_main_ctrl(
		.resetb(resetb),
		.sclk(sclk),
		
		//MCU设置接口
		.cmd_d_ok(cmd_d_ok),
		.cmd_addr(cmd_addr),
		.cmd_data(cmd_data),

		//帧输出模块控制
		.mcu_play_en(mcu_play_en),
		
		.f_start(f_start),
		.f_addr(f_addr),
		.f_size(f_size),
		.h_size(h_size),
		.l_size(l_size),

		//sd播放使能
		.sd_play_en(sd_play_en),
		.force_dis_en(force_dis_en),
		.force_send_play(force_send_play),

		//调试信号
		.tout(sd_tout)
		);

//SD卡数据读取
sd_frame_gen sd_frame_gen(
		.resetb(resetb),
		.sclk(sclk),
		.clk_25M(clk_25M),
		
		.t_ms(time_us[10]),
        	.sync_us(sync_us[0]),
			
		//MCU设置接口
		.cmd_d_ok(cmd_d_ok),
		.cmd_addr(cmd_addr),
		.cmd_data(cmd_data),

		//帧输出起始信号
		.sd_init_ok(sd_init_ok),
		.mcu_play_en(mcu_play_en),
		
		.f_start(f_start),
		.f_addr(f_addr),
		.f_size(f_size),
		.h_size(h_size),
		.l_size(l_size),

		//工作状态标志
		.f_work(f_work),
		.sd_work(sd_work),

		//SD卡控制信号
		.sd_sck(sd_play_clk),
		.sd_cmd_out(sd_play_cmd_out),
		.sd_cmd_oe(sd_play_cmd_oe),
		.sd_dat_in(sd_dat_dis),

		//本地显示信号
		.vsout(vs_sd),
		.h_start(h_start_sd),
		.h_num(h_num_sd),
		.dsout(ds_sd),
		.dout(data_sd),

		//网口发送信号
		.send_flag(send_flag_sd),
		.pre_flag(pre_flag_sd),
		.send_data(send_data_sd),

		//调试信号
		.tout(sd_f_tout)
		);

//**************************************************************
//		   mcu写本地缓冲模拟SD卡
//**************************************************************
sd_sram_buf sram_buf(
		.resetb(resetb),
		.sclk(sclk),

		//MCU设置接口
		.cmd_d_ok(cmd_d_ok),
		.cmd_addr(cmd_addr),
		.cmd_data(cmd_data),
		
		//帧输出模块控制
		.f_work(f_work),
		.f_addr(f_addr),
		.l_size(l_size),
		
		//MCU显示数据产生
 		.sd_sck(sd_play_clk),
		.sd_cmd_oe(sd_play_cmd_oe),
		.sd_dat_mcu(sd_dat_mcu),
		.tout()
		);

//************************************************************/
//		调试接口
//************************************************************/
//assign	tout = {pre_flag_sd, send_flag_sd, ds_sd, vs_sd, f_work, sd_dat3_cs, sd_dat2, sd_dat1, sd_dat0_sdo, sd_cmd_oe, sd_cmd_out, sd_cmd_in, sd_clk};
//assign	tout = {sd_f_tout[31:16], 8'h00,sd_f_tout[1:0]};
//assign	tout = {sd_f_tout[31:16], sdcard_state[5:0], sd_cmd_in, sd_clk, 2'h0, mcu_sd_en, f_start, sd_work, sd_init_ok, sd_valid, sdcard_state[0]};
assign	tout = {sd_f_tout[31:16], sd_dat3_cs, sd_dat2, sd_dat1, sd_dat0_sdo, sd_cmd_oe, sd_cmd_out, sd_cmd_in, sd_clk, 2'h0, mcu_sd_en, f_start, sd_work, sd_init_ok, sd_f_tout[1], sdcard_state[0]};

endmodule
